using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace IQIGame.Onigao.Game.Editors
{
    public class CfgFSMConditionNode : EdtCfgFSMNode
    {
        public string sourceId { get; private set; }
        public string targetId { get; private set; }

        public List<EdtCfgFSMConditionPart> conditionParts = new List<EdtCfgFSMConditionPart>();

        public override void Init(XmlElement element, string fsmShortPath)
        {
            base.Init(element, fsmShortPath);
            sourceId = element.GetAttribute("source");
            targetId = element.GetAttribute("target");
            string leftText = _text.Trim();
            if (string.IsNullOrEmpty(leftText))
            {
                return;
            }
            LogicOperation prevOp = LogicOperation.None;
            do
            {
                int logicOPIndex = GetNextLogicOPIndex(leftText);
                string condPartText;
                string logicOP;
                if (logicOPIndex == -1)
                {
                    condPartText = leftText;
                    leftText = string.Empty;
                    logicOP = string.Empty;
                }
                else
                {
                    string frontTextPart = leftText.Substring(0, logicOPIndex).TrimEnd();
                    logicOP = leftText.Substring(logicOPIndex, 2);
                    string backTextPart = leftText.Substring(logicOPIndex + 2).TrimStart();
                    condPartText = frontTextPart;
                    leftText = backTextPart;
                }
                EdtCfgFSMConditionPart part = new EdtCfgFSMConditionPart();
                if (part.Init(condPartText, prevOp))
                {
                    conditionParts.Add(part);
                }
                else
                {
                    UnityEngine.Debug.LogError($"条件配置错误，sourceId {sourceId}, targetId {targetId}。");
                    return;
                }

                if (logicOP == "&&")
                {
                    prevOp = LogicOperation.And;
                }
                else if (logicOP == "||")
                {
                    prevOp = LogicOperation.Or;
                }
            }
            while (!string.IsNullOrEmpty(leftText));
        }

        private int GetNextLogicOPIndex(string text)
        {
            int logicOperatorIndex = text.IndexOf("&&");
            if (logicOperatorIndex == -1)
            {
                logicOperatorIndex = text.IndexOf("||");
            }
            return logicOperatorIndex;
        }

        public CFSMConditionCfg ToConfig(Dictionary<string, int> strIdToIntIdMap)
        {
            CFSMConditionCfg cfg = new CFSMConditionCfg();
            cfg.id = strIdToIntIdMap[id];
            cfg.parts = new List<CFSMConditionPartCfg>();
            foreach (var part in conditionParts)
            {
                cfg.parts.Add(part.ToConfig());
            }
            cfg.nextStateId = strIdToIntIdMap[targetId];
            return cfg;
        }

        public void GenCode(string rootPath, string privateDirPath, string entityClassName)
        {
            string commonDirPath = rootPath + "/" + EdtCFSMConst.CommonCondFuncRoot;
            //if (!Directory.Exists(commonDirPath))
            //{
            //    Directory.CreateDirectory(commonDirPath);
            //}
            if (!Directory.Exists(privateDirPath))
            {
                Directory.CreateDirectory(privateDirPath);
            }
            string[] commonFiles = Directory.GetFiles(commonDirPath);
            HashSet<string> existCommonCondNames = new HashSet<string>();
            foreach (string commonFile in commonFiles)
            {
                string name = Path.GetFileNameWithoutExtension(commonFile);
                if (name.StartsWith(EdtCFSMConst.CondFuncCSFilePrefix))
                {
                    existCommonCondNames.Add(name);
                }
            }
            foreach (EdtCfgFSMConditionPart part in conditionParts)
            {
                if (string.IsNullOrEmpty(part.funcName))
                {
                    UnityEngine.Debug.LogError("存在包含空方法名的条件。");
                    continue;
                }
                //目前默认规范是：如果首字母是小写则判断为公共条件，不生成代码，公共条件手动添加
                //后续增加Unity编辑工具，不再依赖yEd Graph Editor，将直接在编辑器上选择是否是公共条件。
                bool isPublic = part.isPublic;
                string codeName;
                string codeFilePath;
                string baseClassStr;
                //公共条件直接过滤，不生成代码
                if (isPublic)
                {
                    codeName = $"{EdtCFSMConst.CondFuncCSFilePrefix}{part.funcName}";
                    if (!existCommonCondNames.Contains(codeName))
                    {
                        UnityEngine.Debug.LogError($"{part.funcName}首字母是小写（符合公共条件规范），但未发现任何代码。");
                    }
                    continue;
                    //codeFilePath = $"{commonDirPath}/{codeName}.cs";
                    //baseClassStr = "BaseConditionFunc";
                }
                else
                {
                    codeName = part.GetCodeFileName(_fsmShortPath, out string codeModuleName);
                    codeFilePath = $"{privateDirPath}/{codeName}.cs";
                    baseClassStr = $"CFSMConditionFunc<{entityClassName}, CFSM{codeModuleName}Data>";
                }
                string codeContent = $@"using IQIGame.Onigao.Game;

namespace IQIGame.Onigao.GamePlay
{{
    public class {codeName} : {baseClassStr}
    {{
        protected override void OnInit()
        {{

        }}

        public {part.targetType.FullName} GetValue()
        {{
            //todo 根据业务逻辑返回用于比较的数据（{part.funcName}），策划配置的参数在paramList中获取
            return {GetDefaultValue(part.targetType)};
        }}

        public override bool Check()
        {{
            return Compare(GetValue());
        }}

        public override void OnReset()
        {{
            base.OnReset();
        }}
    }}
}}
";
                if (!File.Exists(codeFilePath))
                {
                    File.WriteAllText(codeFilePath, codeContent);
                    UnityEngine.Debug.Log($"生成了代码：{Path.GetFileName(codeFilePath)}");
                }
            }
        }

        private static string GetDefaultValue(Type t)
        {
            // 判断是否为值类型
            if (t.IsValueType)
            {
                return Activator.CreateInstance(t).ToString().ToLower();
            }
            // 引用类型的默认值是 null
            return "null";
        }
    }
}